﻿/*
SkyFire 2016-04-28
*/

#ifndef THREAD_POOL_H_
#define THREAD_POOL_H_
#include <thread>
#include <condition_variable>
#include <mutex>

template<size_t sz=8>
class _ThreadPool {
private:
    size_t maxRunSize;													//最大允许运行线程数量
    size_t currSize;													//当前运行线程数量
    std::mutex currSizeMu;														//currSize锁
    std::mutex waitNumMu;												//waitNum锁
    std::mutex condMu;													//条件变量锁
	std::mutex maxRunSizeMu;											//maxRunSize锁
    size_t waitNum;														//等待中的线程数量
    std::condition_variable cond;										//条件变量
public:
    void setMaxRunSize(size_t);											//设置最多运行数量
    _ThreadPool(int maxRunSize_t=sz);										//参数为同时可运行的最多线程数量
    template<typename U, typename...T>
    bool addThread(U(*func)(T...), T...args);							//带参数的线程加入,如果线程函数参数不等于传入的实际参数，返回false，否则返回0
    template<typename U>
    void addThread(U(*func)());											//无参的线程加入
	template<typename U, typename...T>
    bool addThreadRef(U(*func)(T&...), T&...args);						//(引用版本)带参数的线程加入,如果线程函数参数不等于传入的实际参数，返回false，否则返回0
};

template<size_t sz>
template<typename U, typename...T>
inline bool _ThreadPool<sz>::addThread(U(*func)(T...), T...args) {          
    std::thread([=]()->void {                                          
        currSizeMu.lock();
		maxRunSizeMu.lock();
        if(currSize < maxRunSize) {                                    
			maxRunSizeMu.unlock();
            currSizeMu.unlock();
        } else {                                                       
			maxRunSizeMu.unlock();
            currSizeMu.unlock();
            waitNumMu.lock();
            ++waitNum;
            waitNumMu.unlock();
            std::unique_lock<std::mutex> lk{ condMu };
            cond.wait(lk);
        }
        currSizeMu.lock();
        currSize++;                                                    
        currSizeMu.unlock();
        func(args...);                                                 
        currSizeMu.lock();
        --currSize;                                                    
        currSizeMu.unlock();
        waitNumMu.lock();
        if(waitNum > 0) {                                              
            std::lock_guard<std::mutex> lk{ condMu };
            --waitNum;                                                 
            cond.notify_one();
        }
        waitNumMu.unlock();
    }).detach();
    return true;
}

template<size_t sz>
template<typename U>
inline void _ThreadPool<sz>::addThread(U(*func)()) {
    std::thread([=]()->void {
        currSizeMu.lock();
		maxRunSizeMu.lock();
        if(currSize < maxRunSize) {
			maxRunSizeMu.unlock();
            currSizeMu.unlock();
        } else {
			maxRunSizeMu.unlock();
            currSizeMu.unlock();
            waitNumMu.lock();
            ++waitNum;
            waitNumMu.unlock();
            std::unique_lock<std::mutex> lk{ condMu };
            cond.wait(lk);
        }
        currSizeMu.lock();
        currSize++;
        currSizeMu.unlock();
        func();
        currSizeMu.lock();
        --currSize;
        currSizeMu.unlock();
        waitNumMu.lock();
        if(waitNum > 0) {
            std::lock_guard<std::mutex> lk{ condMu };
            --waitNum;
            cond.notify_one();
        }
        waitNumMu.unlock();
    }).detach();
}

template<size_t sz>
template<typename U, typename...T>
inline bool _ThreadPool<sz>::addThreadRef(U(*func)(T&...), T&...args) {     
	std::thread([&]()->void {                                          
        currSizeMu.lock();
		maxRunSizeMu.lock();
        if(currSize < maxRunSize) {                                    
			maxRunSizeMu.unlock();
            currSizeMu.unlock();
        } else {                                                       
			maxRunSizeMu.unlock();
            currSizeMu.unlock();
            waitNumMu.lock();
            ++waitNum;
            waitNumMu.unlock();
            std::unique_lock<std::mutex> lk{ condMu };
            cond.wait(lk);
        }
        currSizeMu.lock();
        currSize++;                                                    
        currSizeMu.unlock();
        func(args...);                                                 
        currSizeMu.lock();
        --currSize;                                                    
        currSizeMu.unlock();
        waitNumMu.lock();
        if(waitNum > 0) {                                              
            std::lock_guard<std::mutex> lk{ condMu };
            --waitNum;                                                 
            cond.notify_one();
        }
        waitNumMu.unlock();
    }).detach();
    return true;
}

template<size_t sz>
_ThreadPool<sz>::_ThreadPool(int maxRunSize_t) :maxRunSize(maxRunSize_t), currSize(0), waitNum(0) {}

template<size_t sz>
void _ThreadPool<sz>::setMaxRunSize(size_t maxSz){
	maxRunSizeMu.lock();
    maxRunSize=maxSz;
	maxRunSizeMu.unlock();
}

typedef _ThreadPool<8> ThreadPool;

#endif
